﻿using System;
using System.Collections.Generic;
using System.Text;

using DashFire;
using UnityEngine;
using UnityEditor;
using System.IO;

/// <summary>
/// !!!!!!!!
/// ResBuildConfig中的所有配置运行时都将从Assets/AssetBundle/Config.txt中读入，
/// 如需更改，运行插件AssetBundle/Windows/Config，并执行Apply按钮
/// </summary>
public class ResChapterInfo
{
  public int ResChapterIndex = 0;
  public string ResChapterIdContent = string.Empty;
  public HashSet<int> ResChapterIdList = new HashSet<int>();
}
public class ResBuildDirConfig
{
  public int ResBuildDirIndex = 0;
  public string ResBuildDirs = "";
  public string ResBuildPattern = "";
  public string ResBuildAssetPattern = "";
}
public class ResBuildConfig
{
  public static string ResHomePath = "Assets/AssetBundle";
  public static string[] ConfigSplit = new string[] { ";", "|", };
  public static int VersionSlot = 3;
  public static string[] VersinNumSplitInterval = new string[] { "." };
  public static string ConfigFile = "Assets/AssetBundle/Config.txt";
  public static string LogTimeFormat = "yyyyMMddHHmmss";

  // GameConfig
  public static string Version = "1.0.1";
  public static string GroupName = "dev";
  public static string ResServerURL = "http://192.168.1.30";

  // BuildConfig
  public static string ResBuildConfigOutputPath = "assets/AssetBundle/build";
  public static string ResBuildConfigFilePath = "ResBuildConfig_ab.txt";
  public static string ResBuildConfigFormat = "{0}	{1}	{2}	{3}	{4}	{5}	{6}	{7}	{8}";
  public static string ResBuildConfigHeader = "Id	Resources	ResourcesShortName	TargetName	MD5	Size	Guid	IsNeedBuild	Dependency";
  public static int ResBuildDirConfigsCount = 0;
  public static List<ResBuildDirConfig> ResBuildDirConfigs = new List<ResBuildDirConfig>();
  public static string ResBuildDiffFilePath = "ResBuildDiff_ab.txt";

  // BuildOption
  public static BuildTarget BuildOptionTarget = BuildTarget.StandaloneWindows;
  public static BuildAssetBundleOptions BuildOptionRes =
                    BuildAssetBundleOptions.CollectDependencies |
                    BuildAssetBundleOptions.DeterministicAssetBundle |
                    BuildAssetBundleOptions.CompleteAssets;
  public static BuildOptions BuildOptionScene =
                  BuildOptions.UncompressedAssetBundle;
  public static BuildOptions BuildOptionPlayer = BuildOptions.None;
  public static string BuildOptionExtend = ".ab";
  public static bool BuildOptionZip = true;
  public static bool BuildOptionEncode = false;

  // ResVersion
  public static string ResVersionFilePath = "ResVersion_ab.txt";
  public static string ResVersionZipPath = "ResVersion.ab";
  public static string ResVersionFormat = "{0}	{1}	{2}	{3}	{4}	{5}";
  public static string ResVersionHeader = "AssetBundleName	AssetName	AssetShortName	MD5	Size	Version";

  public static string ResVersionClientFilePath = "ClientResVersion_ab.txt";
  public static string ResVersionClientFormat = "{0}	{1}	{2}	{3}	{4}";
  public static string ResVersionClientHeader = "AssetBundleName	AssetName	AssetShortName	MD5	Size";

  // ResSheet
  public static string ResSheetFilePath = "list.txt";
  public static string ResSheetZipPath = "ResSheet.ab";
  public static string ResSheetPattern = ".txt;.map;.dsl;.obs";
  public static string ResSheetCachePath = "DataFile/";

  // Version
  public static string VersionClientFile = "ClientVersion.txt";
  public static string VersionServerFile = "ServerVersion.txt";

  // ResLog
  public static string ResLogFilePath = "assets/../build/log/build_{0}_{1}_{2}.log";

  // ResCommit
  public static string ResCommitSearchPattern = "*.ab;*.txt";
  public static string ResCommitBuildInPath = "Assets/StreamingAssets/ResFile/";
  public static string ResCommitCachePath = "ResFile/";
  public static string ResStreamingAssetPath = "Assets/StreamingAssets/Client;Assets/StreamingAssets/Public;Assets/StreamingAssets/list.txt;";

  // Extend
  public static string ResFinderShaderFilePath = "ResFinderShader.txt";
  public static string ResFinderTypeFilePath = "ResFinderType.txt";
  public static string ResFinderTypeTargetDir = "assets/";
  public static string ResFinderTypeExcludePattern = ".meta;.svn";
  public static string ResFinderTypeIncludePattern = "*";

  public static bool SetBuildTargetPlatform(BuildTarget target)
  {
    BuildOptionTarget = target;
    return true;
  }
  public static bool Load()
  {
    bool ret = false;
    try {
      ConfigFile iniFile = new ConfigFile(ResBuildHelper.GetFilePathAbs(ConfigFile));

      //GameConfig
      Version = iniFile.GetSetting("GameConfig", "Version");
      GroupName = iniFile.GetSetting("GameConfig", "GroupName");
      ResServerURL = iniFile.GetSetting("GameConfig", "ResServerURL");

      //BuildConfig
      ResBuildConfigOutputPath = iniFile.GetSetting("BuildConfig", "ResBuildConfigOutputPath");
      ResBuildConfigFilePath = iniFile.GetSetting("BuildConfig", "ResBuildConfigFilePath");
      ResBuildConfigFormat = iniFile.GetSetting("BuildConfig", "ResBuildConfigFormat");
      ResBuildConfigHeader = iniFile.GetSetting("BuildConfig", "ResBuildConfigHeader");
      string strResBuildDirConfigsCount = iniFile.GetSetting("BuildConfig", "ResBuildDirConfigsCount").Trim();
      if (!int.TryParse(strResBuildDirConfigsCount, out ResBuildDirConfigsCount)) {
        ResBuildDirConfigsCount = 0;
      }
      ResBuildDirConfigs.Clear();
      for (int index = 1; index <= ResBuildDirConfigsCount; index++) {
        ResBuildDirConfig info = new ResBuildDirConfig();
        info.ResBuildDirIndex = index;
        string resBuildDirs = iniFile.GetSetting("BuildConfig", "ResBuildDirs" + index);
        info.ResBuildDirs = resBuildDirs;
        string resBuildPattern = iniFile.GetSetting("BuildConfig", "ResBuildPattern" + index);
        info.ResBuildPattern = resBuildPattern;
        string resBuildAssetPattern = iniFile.GetSetting("BuildConfig", "ResBuildAssetPattern" + index);
        info.ResBuildAssetPattern = resBuildAssetPattern;
        ResBuildDirConfigs.Add(info);
      }

      // BuildOption
      BuildOptionRes = ConvertStrToBuildOptionRes(iniFile.GetSetting("BuildOption", "BuildOptionRes"));
      BuildOptionPlayer = ConvertStrToBuildOptionPlayer(iniFile.GetSetting("BuildOption", "BuildOptionPlayer"));
      BuildOptionTarget = ConvertStrToBuildTarget(iniFile.GetSetting("BuildOption", "BuildOptionTarget"));
      BuildOptionExtend = iniFile.GetSetting("BuildOption", "BuildOptionExtend");
      BuildOptionZip = Convert.ToBoolean(iniFile.GetSetting("BuildOption", "BuildOptionZip"));
      BuildOptionEncode = Convert.ToBoolean(iniFile.GetSetting("BuildOption", "BuildOptionEncode"));

      // ResVersion
      ResVersionFilePath = iniFile.GetSetting("ResVersion", "ResVersionFilePath");
      ResVersionZipPath = iniFile.GetSetting("ResVersion", "ResVersionZipPath");
      ResVersionFormat = iniFile.GetSetting("ResVersion", "ResVersionFormat");
      ResVersionHeader = iniFile.GetSetting("ResVersion", "ResVersionHeader");

      ResVersionClientFilePath = iniFile.GetSetting("ResVersion", "ResVersionClientFilePath");
      ResVersionClientFormat = iniFile.GetSetting("ResVersion", "ResVersionClientFormat");
      ResVersionClientHeader = iniFile.GetSetting("ResVersion", "ResVersionClientHeader");

      // Version
      VersionClientFile = iniFile.GetSetting("Version", "VersionClientFile");
      VersionServerFile = iniFile.GetSetting("Version", "VersionServerFile");

      // ResLog
      ResLogFilePath = iniFile.GetSetting("ResLog", "ResLogFilePath");

      // ResCommit
      ResCommitSearchPattern = iniFile.GetSetting("ResCommit", "ResCommitSearchPattern");
      ResCommitBuildInPath = iniFile.GetSetting("ResCommit", "ResCommitBuildInPath");
      ResCommitCachePath = iniFile.GetSetting("ResCommit", "ResCommitCachePath");

      // Extend
      ResFinderShaderFilePath = iniFile.GetSetting("Extend", "ResFinderShaderFilePath");
      ResFinderTypeFilePath = iniFile.GetSetting("Extend", "ResFinderTypeFilePath");
      ResFinderTypeTargetDir = iniFile.GetSetting("Extend", "ResFinderTypeTargetDir");
      ResFinderTypeExcludePattern = iniFile.GetSetting("Extend", "ResFinderTypeExcludePattern");
      ResFinderTypeIncludePattern = iniFile.GetSetting("Extend", "ResFinderTypeIncludePattern");

      ret = true;
    } catch (System.Exception ex) {
      ResBuildLog.Warn("ResBuildConfig.Load failed, ex:" + ex);
      ret = false;
      return ret;
    }
    ResBuildLog.Info("ResBuildConfig.Load Success");
    return ret;
  }
  public static bool Save()
  {
    if (!ResBuildConfig.Check()) {
      ResBuildLog.Warn("ResBuildConfig.Check Failed");
      return false;
    }

    try {
      ConfigFile iniFile = new ConfigFile(ResBuildHelper.GetFilePathAbs(ConfigFile));

      //GameConfig
      iniFile.AddSetting("GameConfig", "Version", Version);
      iniFile.AddSetting("GameConfig", "GroupName", GroupName);
      iniFile.AddSetting("GameConfig", "ResServerURL", ResServerURL);

      //BuildConfig
      iniFile.AddSetting("BuildConfig", "ResBuildConfigOutputPath", ResBuildConfigOutputPath);
      iniFile.AddSetting("BuildConfig", "ResBuildConfigFilePath", ResBuildConfigFilePath);
      iniFile.AddSetting("BuildConfig", "ResBuildConfigFormat", ResBuildConfigFormat);
      iniFile.AddSetting("BuildConfig", "ResBuildConfigHeader", ResBuildConfigHeader);
      iniFile.AddSetting("BuildConfig", "ResBuildDirConfigsCount", ResBuildDirConfigsCount.ToString());
      for (int index = 0; index < ResBuildDirConfigsCount; index++) {
        ResBuildDirConfig info = ResBuildDirConfigs[index];
        iniFile.AddSetting("BuildConfig", "ResBuildDirs" + (info.ResBuildDirIndex), info.ResBuildDirs);
        iniFile.AddSetting("BuildConfig", "ResBuildPattern" + (info.ResBuildDirIndex), info.ResBuildPattern);
        iniFile.AddSetting("BuildConfig", "ResBuildAssetPattern" + (info.ResBuildDirIndex), info.ResBuildAssetPattern);
      }

      // BuildOption
      iniFile.AddSetting("BuildOption", "BuildOptionRes", ConvertBuildOptionResToStr(BuildOptionRes));
      iniFile.AddSetting("BuildOption", "BuildOptionPlayer", ConvertBuildOptionPlayerToStr(BuildOptionPlayer));
      iniFile.AddSetting("BuildOption", "BuildOptionTarget", ConvertBuildTargetToStr(BuildOptionTarget));
      iniFile.AddSetting("BuildOption", "BuildOptionExtend", BuildOptionExtend);
      iniFile.AddSetting("BuildOption", "BuildOptionZip", BuildOptionZip.ToString());
      iniFile.AddSetting("BuildOption", "BuildOptionEncode", BuildOptionEncode.ToString());

      // ResVersion
      iniFile.AddSetting("ResVersion", "ResVersionFilePath", ResVersionFilePath);
      iniFile.AddSetting("ResVersion", "ResVersionZipPath", ResVersionZipPath);
      iniFile.AddSetting("ResVersion", "ResVersionFormat", ResVersionFormat);
      iniFile.AddSetting("ResVersion", "ResVersionHeader", ResVersionHeader);

      iniFile.AddSetting("ResVersion", "ResVersionClientFilePath", ResVersionClientFilePath);
      iniFile.AddSetting("ResVersion", "ResVersionClientFormat", ResVersionClientFormat);
      iniFile.AddSetting("ResVersion", "ResVersionClientHeader", ResVersionClientHeader);

      // Version
      iniFile.AddSetting("Version", "VersionClientFile", VersionClientFile);
      iniFile.AddSetting("Version", "VersionServerFile", VersionServerFile);

      // ResLog
      iniFile.AddSetting("ResLog", "ResLogFilePath", ResLogFilePath);

      // ResCommit
      iniFile.AddSetting("ResCommit", "ResCommitSearchPattern", ResCommitSearchPattern);
      iniFile.AddSetting("ResCommit", "ResCommitBuildInPath", ResCommitBuildInPath);
      iniFile.AddSetting("ResCommit", "ResCommitCachePath", ResCommitCachePath);

      // Extend
      iniFile.AddSetting("Extend", "ResFinderShaderFilePath", ResFinderShaderFilePath);
      iniFile.AddSetting("Extend", "ResFinderTypeFilePath", ResFinderTypeFilePath);
      iniFile.AddSetting("Extend", "ResFinderTypeTargetDir", ResFinderTypeTargetDir);
      iniFile.AddSetting("Extend", "ResFinderTypeExcludePattern", ResFinderTypeExcludePattern);
      iniFile.AddSetting("Extend", "ResFinderTypeIncludePattern", ResFinderTypeIncludePattern);

      iniFile.SaveSettings();
    } catch (System.Exception ex) {
      ResBuildLog.Warn("ResBuildConfig.Save failed, ex:" + ex);
      return false;
    }
    ResBuildLog.Info("ResBuildConfig.Save Success");
    return true;
  }
  public static bool Check()
  {
    //Version
    string[] splitRet = Version.Split(VersinNumSplitInterval, StringSplitOptions.RemoveEmptyEntries);
    if (splitRet == null || splitRet.Length != VersionSlot) {
      ResBuildLog.Warn("CheckConfig: Version Format Error");
      return false;
    }
    //Platform
    string platform = ResBuildHelper.GetPlatformName(BuildOptionTarget);
    if (string.IsNullOrEmpty(platform)
      || platform.Equals("invalid")) {
      ResBuildLog.Warn("CheckConfig: Platform bindting to BuildOptionTarget,Current Only Suuport win32/mac/android/ios");
      return false;
    }
    string groupName = ResBuildConfig.GroupName;
    if (string.IsNullOrEmpty(groupName)) {
      ResBuildLog.Warn("CheckConfig: GroupName miss, default:dev");
      return false;
    }

    //ResServerURL
    if (string.IsNullOrEmpty(ResServerURL)) {
      ResBuildLog.Warn("CheckConfig: ResServerURL Invalid");
      return false;
    }

    //ResBuildDirs
    for (int index = 1; index <= ResBuildConfig.ResBuildDirConfigsCount; index++) {
      ResBuildDirConfig config = ResBuildConfig.ResBuildDirConfigs[index - 1];
      string[] tResBuildDirs = config.ResBuildDirs.Split(ResBuildConfig.ConfigSplit,
      StringSplitOptions.RemoveEmptyEntries);
      if (tResBuildDirs == null
        || tResBuildDirs.Length == 0) {
        ResBuildLog.Warn("CheckConfig: ResBuildDirs Invalid!");
      } else {
        foreach (String rbd in tResBuildDirs) {
          if (!ResBuildHelper.IsPathValid(rbd)) {
            ResBuildLog.Warn("CheckConfig: ResBuildDirs invalid or not exist,res:" + rbd);
          }
        }
      }
      string[] tResBuildPattern = config.ResBuildPattern.Split(ResBuildConfig.ConfigSplit,
        StringSplitOptions.RemoveEmptyEntries);
      if (tResBuildPattern == null
        || tResBuildPattern.Length == 0) {
        ResBuildLog.Warn("CheckConfig: ResBuildPattern Invalid!");
      } else {
        foreach (String rbd in tResBuildPattern) {
          if (!rbd.ToLower().StartsWith("*.")) {
            ResBuildLog.Warn("CheckConfig: ResBuildPattern MUST startwith '*.',eg.'*.unity;*.prefab'");
          }
        }
      }
    }

    ResBuildLog.Info("ResBuildConfig.Check Success");
    return true;
  }
  public static BuildAssetBundleOptions ConvertStrToBuildOptionRes(string content)
  {
    BuildAssetBundleOptions ret = 0;
    string[] tBuildOptions = content.Split(ConfigSplit, StringSplitOptions.RemoveEmptyEntries);
    foreach (string tOption in tBuildOptions) {
      try {
        ret |= (BuildAssetBundleOptions)Enum.Parse(typeof(BuildAssetBundleOptions), tOption);
      } catch (Exception ex) {
        ResBuildLog.Warn("ConvertBuildAssetBundleOptions error:" + content + " ex:" + ex);
      }
    }
    return ret;
  }
  public static string ConvertBuildOptionResToStr(BuildAssetBundleOptions content)
  {
    string ret = string.Empty;
    Array list = Enum.GetValues(typeof(BuildAssetBundleOptions));
    foreach (int val in list) {
      if (((int)content & (int)val) != 0) {
        ret += Enum.GetName(typeof(BuildAssetBundleOptions), val) + ";";
      }
    }
    return ret;
  }
  public static BuildOptions ConvertStrToBuildOptionPlayer(string content)
  {
    BuildOptions ret = 0;
    string[] tBuildOptions = content.Split(ConfigSplit, StringSplitOptions.RemoveEmptyEntries);
    foreach (string tOption in tBuildOptions) {
      try {
        ret |= (BuildOptions)Enum.Parse(typeof(BuildOptions), tOption);
      } catch (Exception ex) {
        ResBuildLog.Warn("ConvertStrToBuildOptionPlayer error:" + content + " ex:" + ex);
      }
    }
    return ret;
  }
  public static string ConvertBuildOptionPlayerToStr(BuildOptions content)
  {
    string ret = string.Empty;
    Array list = Enum.GetValues(typeof(BuildOptions));
    foreach (int val in list) {
      if (((int)content & (int)val) != 0) {
        ret += Enum.GetName(typeof(BuildOptions), val) + ";";
      }
    }
    if (content == BuildOptions.None) {
      ret = "None";
    }
    return ret;
  }
  public static BuildTarget ConvertStrToBuildTarget(string content)
  {
    BuildTarget ret = BuildTarget.StandaloneWindows;
    try {
      ret = (BuildTarget)Enum.Parse(typeof(BuildTarget), content);
    } catch (Exception ex) {
      ResBuildLog.Warn("ConvertStrToBuildOption error:" + content + " ex:" + ex);
    }
    return ret;
  }
  public static string ConvertBuildTargetToStr(BuildTarget content)
  {
    return Enum.GetName(typeof(BuildTarget), content);
  }
  public static string GetForceDownloadUrl(BuildTarget target)
  {
    switch (target) {
      case BuildTarget.Android: {
        return ResServerURL + "/" + "[group]/df_[group]_[channel].apk";
        }
      case BuildTarget.iOS: {
#if UNITY_APPSTORE
        return "https://itunes.apple.com/cn/app/id955307313";
#else
        return "itms-services://?action=download-manifest&amp;url=https://topic.changyou.com/mjzr/[group]/df_[group]_[channel].plist";
#endif
        }
      case BuildTarget.StandaloneWindows: {
        return ResServerURL + "download.html";
        }
    }
    return string.Empty;
  }
  public static string DumpInfo()
  {
    StringBuilder sb = new StringBuilder();
    sb.AppendLine("ResBuildConfig Info:");
    //GameConfig
    sb.AppendLine("\tGameConfig");
    sb.AppendLine("\t\tVersion=" + Version);
    sb.AppendLine("\t\tGroupName=" + GroupName);
    sb.AppendLine("\t\tResServerURL=" + ResServerURL);

    //BuildConfig
    sb.AppendLine("\tBuildConfig");
    sb.AppendLine("\t\tResBuildConfigOutputPath=" + ResBuildConfigOutputPath);
    sb.AppendLine("\t\tResBuildConfigFilePath=" + ResBuildConfigFilePath);
    sb.AppendLine("\t\tResBuildConfigFormat=" + ResBuildConfigFormat);
    sb.AppendLine("\t\tResBuildConfigHeader=" + ResBuildConfigHeader);
    for (int index = 0; index < ResBuildConfig.ResBuildDirConfigsCount; index++) {
      ResBuildDirConfig config = ResBuildConfig.ResBuildDirConfigs[index];
      sb.AppendLine(string.Format("\t\tResBuildDirs{0}=", index + 1) + config.ResBuildDirs);
      sb.AppendLine(string.Format("\t\tResBuildPattern{0}=", index + 1) + config.ResBuildPattern);
      sb.AppendLine(string.Format("\t\tResBuildAssetPattern{0}=", index + 1) + config.ResBuildAssetPattern);
    }

    // BuildOption
    sb.AppendLine("\tBuildOption");
    sb.AppendLine("\t\tBuildOptionRes=" + ConvertBuildOptionResToStr(BuildOptionRes));
    sb.AppendLine("\t\tBuildOptionPlayer=" + ConvertBuildOptionPlayerToStr(BuildOptionPlayer));
    sb.AppendLine("\t\tBuildOptionTarget=" + ConvertBuildTargetToStr(BuildOptionTarget));
    sb.AppendLine("\t\tBuildOptionExtend=" + BuildOptionExtend);

    // ResVersion
    sb.AppendLine("\tResVersion");
    sb.AppendLine("\t\tResVersionFilePath=" + ResVersionFilePath);
    sb.AppendLine("\t\tResVersionZipPath=" + ResVersionZipPath);
    sb.AppendLine("\t\tResVersionFormat=" + ResVersionFormat);
    sb.AppendLine("\t\tResVersionHeader=" + ResVersionHeader);

    sb.AppendLine("\t\tResVersionClientFilePath=" + ResVersionClientFilePath);
    sb.AppendLine("\t\tResVersionClientFormat=" + ResVersionClientFormat);
    sb.AppendLine("\t\tResVersionClientHeader=" + ResVersionClientHeader);

    // Version
    sb.AppendLine("\tVersion");
    sb.AppendLine("\t\tVersionClientFile=" + VersionClientFile);
    sb.AppendLine("\t\tVersionServerFile=" + VersionServerFile);

    // ResLog
    sb.AppendLine("\tResLog");
    sb.AppendLine("\t\tResLogFilePath=" + ResLogFilePath);

    // ResCommit
    sb.AppendLine("\tResCommit");
    sb.AppendLine("\t\tResCommitSearchPattern=" + ResCommitSearchPattern);
    sb.AppendLine("\t\tResCommitBuildInPath=" + ResCommitBuildInPath);
    sb.AppendLine("\t\tResCommitCachePath=" + ResCommitCachePath);

    // Extend
    sb.AppendLine("\tExtend");
    sb.AppendLine("\t\tResFinderShaderFilePath=" + ResFinderShaderFilePath);
    sb.AppendLine("\t\tResFinderTypeFilePath=" + ResFinderTypeFilePath);
    sb.AppendLine("\t\tResFinderTypeTargetDir=" + ResFinderTypeTargetDir);
    sb.AppendLine("\t\tResFinderTypeExcludePattern=" + ResFinderTypeExcludePattern);
    sb.AppendLine("\t\tResFinderTypeIncludePattern=" + ResFinderTypeIncludePattern);

    return sb.ToString();
  }
}
